<template>
  <a-modal
    v-model:open="visible"
    title="代码预览"
    width="80%"
    :footer="null"
    @cancel="handleCancel"
    :maskClosable="false"
    wrapClassName="code-preview-modal"
  >
    <div class="code-preview-container">
      <div class="file-tree-panel" :style="{ width: treeWidth + 'px' }">
        <a-directory-tree
          :tree-data="fileTree"
          :expandedKeys="expandedKeys"
          @expand="onExpand"
          @select="onSelect"
          :selectedKeys="selectedKeys"
        />
      </div>
      <div class="drag-bar" @mousedown="startDrag"></div>
      <div
        class="code-editor-panel"
        :style="{ width: `calc(100% - ${treeWidth}px - 5px)` }"
      >
        <div v-if="currentFile" class="file-header">
          <span class="file-name">{{ currentFile.name }}</span>
          <a-button type="primary" size="small" @click="downloadCurrentFile">
            下载文件
          </a-button>
        </div>
        <div v-if="currentFile" class="editor-container">
          <codemirror
            v-model="currentFile.content"
            :extensions="getEditorExtensions(currentFile.name)"
            :style="{ height: '100%' }"
            :disabled="true"
          />
        </div>
        <div v-else class="no-file-selected">
          <a-empty description="请选择一个文件进行预览" />
        </div>
      </div>
    </div>

    <div class="modal-footer">
      <a-button @click="handleCancel">关闭</a-button>
      <a-button @click="copyToClipboard" :loading="copying" :disabled="!currentFile">
        {{ copying ? '复制中...' : '复制代码' }}
      </a-button>
      <a-button type="primary" @click="downloadAll">下载全部代码</a-button>
    </div>
  </a-modal>
</template>

<script setup>
import { ref, computed, watch } from "vue";
import { message } from "ant-design-vue";
import { Codemirror } from "vue-codemirror";
import { javascript } from "@codemirror/lang-javascript";
import { vue } from "@codemirror/lang-vue";
import { json } from "@codemirror/lang-json";
import { html } from "@codemirror/lang-html";
import { css } from "@codemirror/lang-css";
import { less } from "@codemirror/lang-less";

const props = defineProps({
  open: {
    type: Boolean,
    default: false,
  },
  files: {
    type: Array,
    default: () => [],
  },
});

const emit = defineEmits(["update:open", "download-all"]);

// 控制模态框显示
const visible = computed({
  get: () => props.open,
  set: (val) => {
    emit("update:open", val);
  },
});

const copying = ref(false);

watch(
  () => props.open,
  (val) => {
    if (!val) {
      currentFile.value = null;
      selectedKeys.value=[];
    }
  }
);

// 左侧文件树宽度
const treeWidth = ref(300);

// 拖拽相关状态
const isDragging = ref(false);
const startX = ref(0);
const startWidth = ref(0);

// 文件树数据
const fileTree = computed(() => {
  const tree = [];
  const map = {};

  // 初始化根节点
  map[""] = tree;

  // 处理每个文件
  props.files.forEach((file) => {
    // 统一路径分隔符为 /
    const normalizedPath = file.path.replace(/\\/g, '/');
    const pathParts = normalizedPath.split('/');

    let currentPath = "";

    pathParts.forEach((part, index) => {
      const isFile = index === pathParts.length - 1;
      const fullPath = currentPath ? `${currentPath}/${part}` : part;

      if (!map[fullPath]) {
        const node = {
          title: part,
          key: fullPath,
        };

        if (isFile) {
          node.isLeaf = true;
          node.file = file;
        } else {
          node.children = [];
        }

        // 添加到父节点
        if (map[currentPath]) {
          map[currentPath].push(node);
        }

        // 注册到map
        if (!isFile) {
          map[fullPath] = node.children;
        }
      }

      currentPath = fullPath;
    });
  });

  return tree;
});

// 展开的节点
const expandedKeys = ref([]);
const selectedKeys = ref([]);

// 当前选中的文件
const currentFile = ref(null);

// 处理节点展开
const onExpand = (keys) => {
  expandedKeys.value = keys;
};

// 处理节点选择
const onSelect = (keys, event) => {
  selectedKeys.value = keys;
  if (keys.length > 0) {
    const node = event.node;
    if (node.file) {
      currentFile.value = node.file;
    }
  } else {
    currentFile.value = null;
  }
};

// 获取编辑器扩展
const getEditorExtensions = (fileName) => {
  const extensions = [];

  if (fileName.endsWith(".js") || fileName.endsWith(".ts")) {
    extensions.push(javascript());
  } else if (fileName.endsWith(".vue")) {
    extensions.push(vue());
  } else if (fileName.endsWith(".json")) {
    extensions.push(json());
  } else if (fileName.endsWith(".html")) {
    extensions.push(html());
  } else if (fileName.endsWith(".css")) {
    extensions.push(css());
  } else if (fileName.endsWith(".less")) {
    extensions.push(less());
  } else if (fileName.endsWith(".tsx") || fileName.endsWith(".jsx")) {
    // 使用javascript语言支持并启用typescript和jsx选项
    extensions.push(javascript({ typescript: true, jsx: true }));
  }

  return extensions;
};

// 开始拖拽
const startDrag = (e) => {
  isDragging.value = true;
  startX.value = e.clientX;
  startWidth.value = treeWidth.value;

  // 添加全局事件监听器
  document.addEventListener("mousemove", doDrag);
  document.addEventListener("mouseup", stopDrag);

  // 防止文本选择
  document.body.style.userSelect = "none";
  document.body.style.cursor = "col-resize";
};

// 执行拖拽
const doDrag = (e) => {
  if (!isDragging.value) return;

  const diff = e.clientX - startX.value;
  const newWidth = startWidth.value + diff;

  // 限制最小和最大宽度
  treeWidth.value = Math.max(250, Math.min(500, newWidth));
};

// 停止拖拽
const stopDrag = () => {
  isDragging.value = false;

  // 移除全局事件监听器
  document.removeEventListener("mousemove", doDrag);
  document.removeEventListener("mouseup", stopDrag);

  // 恢复样式
  document.body.style.userSelect = "";
  document.body.style.cursor = "";
};

// 下载当前文件
const downloadCurrentFile = () => {
  if (!currentFile.value) return;

  const blob = new Blob([currentFile.value.content], {
    type: "text/plain;charset=utf-8",
  });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = currentFile.value.name;
  link.click();
  URL.revokeObjectURL(url);
};

// 下载全部代码
const downloadAll = () => {
  emit("download-all");
};

// 关闭模态框
const handleCancel = () => {
  visible.value = false;
};

// 复制到剪贴板
const copyToClipboard = async () => {
  if (!currentFile.value) return;
  
  copying.value = true;
  
  try {
    // 检查浏览器是否支持Clipboard API
    if (navigator.clipboard && window.isSecureContext) {
      await navigator.clipboard.writeText(currentFile.value.content);
    } else {
      // 降级处理：使用传统的execCommand('copy')方法
      const textArea = document.createElement('textarea');
      textArea.value = currentFile.value.content;
      document.body.appendChild(textArea);
      textArea.focus();
      textArea.select();

      const successful = document.execCommand('copy');
      document.body.removeChild(textArea);

      if (!successful) {
        throw new Error('execCommand failed');
      }
    }
    
    // 复制成功提示
    message.success('代码已复制到剪贴板');
  } catch (err) {
    console.error('复制失败:', err);
    message.error('复制失败，请手动复制');
  } finally {
    copying.value = false;
  }
};

// 监听文件变化，初始化展开状态
watch(
  () => props.files,
  (newFiles) => {
    if (newFiles.length > 0) {
      // 展开所有节点
      const getAllKeys = (nodes) => {
        let keys = [];
        nodes.forEach(node => {
          keys.push(node.key);
          if (node.children && node.children.length > 0) {
            keys = keys.concat(getAllKeys(node.children));
          }
        });
        return keys;
      };
      const allKeys = getAllKeys(fileTree.value);
      expandedKeys.value = allKeys;
    }
  },
  { immediate: true }
);

// 监听模态框关闭，重置宽度
watch(
  () => props.open,
  (newVal) => {
    if (!newVal) {
      // 重置为默认宽度
      treeWidth.value = 300;
    }
  }
);
</script>

<style scoped>
.code-preview-container {
  display: flex;
  height: 60vh;
  border: 1px solid #f0f0f0;
  border-radius: 4px;
  overflow: hidden;
}

.file-tree-panel {
  min-width: 150px;
  max-width: 500px;
  border-right: 1px solid #f0f0f0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 12px;
  box-sizing: border-box;
  background-color: #ffffff;
}

.drag-bar {
  width: 5px;
  background-color: #e8e8e8;
  cursor: col-resize;
  transition: background-color 0.2s;
  flex-shrink: 0;
}

.drag-bar:hover {
  background-color: #1890ff;
}

.code-editor-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0; /* 防止flex项目溢出 */
}

.file-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  border-bottom: 1px solid #f0f0f0;
  background-color: #fff;
}

.file-name {
  font-weight: 500;
  color: #1890ff;
}

.editor-container {
  flex: 1;
  overflow: hidden;
}

.no-file-selected {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 20px;
}

:deep(.ant-tree-node-content-wrapper){
  display: flex;
}
</style>
